package core.evolutionary;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import core.IEnvironment;
import core.Problem;
import core.Result;

public class EvolutionaryEnvironment implements IEnvironment {
	private Set<Island> islands;
	private Set<Edge> edges;
	private Set<Agent> agents;
	private Problem problem;
//	private int counter; 
	
	public EvolutionaryEnvironment(Problem problem) {
		this.islands = new HashSet<Island>();
		this.edges = new HashSet<Edge>();
		this.agents = new HashSet<Agent>();
		this.problem = problem;
	}
	
	public boolean add(Agent e) {
//		System.out.println(counter++);
		return agents.add(e);
	}
	
	public boolean remove(Agent e) {
		return agents.remove(e);
	}

	public boolean add(Edge e) {
		return edges.add(e);
	}

	public boolean add(Island e) {
		return islands.add(e);
	}
	
	public Set<Edge> getEdges(Island fromIsland, boolean elitist) {
		HashSet<Edge> tmp = new HashSet<Edge>();
		for(Edge el:this.edges) {
			if(el.joinsWith(fromIsland, elitist)) {
				tmp.add(el);
			}
		}
		return tmp;
	}
	
	/* (non-Javadoc)
	 * @see core.IEnvironment#step()
	 */
	public void step() {
		Object[] tmp = this.agents.toArray();
//		System.out.println(tmp.length);
		int i=0;
		try{
		while(true) {
			
			((Agent)tmp[i]).lifeStep();

			i++;
		}
		} catch (ArrayIndexOutOfBoundsException e) {
			//tu nic nie robimy
		}
		
		for(Island isl: this.islands) {
			isl.makeNewAgents();
		}
		
//		System.out.println(this.agents.toArray().length);
	}
	
	/* (non-Javadoc)
	 * @see core.IEnvironment#getResults(boolean)
	 */
	public Set<Result> getResults(boolean nonDominated) throws Exception {
		Set<Result> results = new HashSet<Result>();
		double[] tmpResults;
		Object[] it = (Object[]) this.agents.toArray();
		int j=0;
		try {
		while(true) {
			Agent agent = (Agent) it[j];
			j++;
			boolean fail = false;
			tmpResults = agent.getResults();
			if(nonDominated && results.size() > 0) {
				Iterator<Result> iterator = results.iterator();
				while(iterator.hasNext()) {
					Result tmp = iterator.next();
					if(problem.isFirstDominatingTheOther(tmp.result, tmpResults)) {
						fail = true;
						break;
					}
				}
				
				if(fail) {
					continue;
				}
				
				iterator = results.iterator();
				while(iterator.hasNext()) {
					Result tmp = iterator.next();
					if(problem.isFirstDominatingTheOther(tmpResults, tmp.result)) {
						iterator.remove();
//						results.remove(tmp);
					}
				}
				//FIXME nie wiem, gdzie de facto tutaj trzymany jest genotyp dla biezacego result - czy w agent.genotype?
				results.add(new Result(agent.genotype,tmpResults));
			} else {
				results.add(new Result(agent.genotype,tmpResults));
			}
		}
		} catch (IndexOutOfBoundsException e) {}
		
		return results;
	}

	/* (non-Javadoc)
	 * @see core.IEnvironment#resetResults()
	 */
	public void resetResults() {
		for(Agent agent: this.agents) {
			agent.resetResults();
		}
	}

	public Set<Island> getIslands(boolean elitist) {
		Set<Island> tmp = new HashSet<Island>();
		for(Island isl:this.islands) {
			if(isl.isElitist()==elitist) {
				tmp.add(isl);
			}
		}
		return tmp;
	}

	public Set<Island> getIslands() {
		return this.getIslands(false);
	}
	
//	public Island makeIsland() {
//		
//	}
}
